<?php

/*
 * this control use to manage membership, tasks in this control include:
 * 1)apply for membership
 * 2)approve membership
 * 3)assign role to customer
 * 
 */

class BUIMembership extends BUIControl {

    const Show_ApplyFor_Membership = 'showApplyForMembership';
    const Show_Approve_Membership = 'showApproveMembership';
    const Show_Delete_Membership = 'showDeleteMembership';
    const Show_Admin_Membership = 'showAdminMembership';
    const Show_User_Membership = 'showUserMembership';
    const Approve_Apply = 'approveApply';
    const Reject_Apply = 'rejectApply';
    const Submit_Apply = 'submitApply';
    const Delete_Apply = 'deleteApply';
    const Process_Apply_For_Member = 'processApplyForMember';
    const Add_Allow_Apply_Role = 'addAllowApplyRole';
    const Delete_Allow_Apply_Role = 'deleteAllowApplyRole';

    public function onRun($data = NULL) {

        $sender = Blyn::app()->getUIManager()->getSenderControl();
        $updateControl = Blyn::app()->getUIManager()->getUpdateControl();
        $activeLink = Blyn::app()->getUIManager()->getActiveLink();
        $theme = Blyn::app()->getUIManager()->getTheme();
        $result = NULL;

        //first populate available roles for space
        $this->populateAvailableApplyRole();

        //below code used for adjusting theme control
        $control = new BUIControl('membershipControl');
        if ($theme == BUIBlyn::Theme_Mobile_Bootstrap) {
            $control = new BUIWXControl('membershipControl');
        }

        //if ($updateControl->name != 'memberControl') {
        //$updateControl->addChildControl($control, 'memberControl');
        //}
//        if ($sender->isLinkClicked('manageBooking')) {
//            $this->addChildControl($control);
//            $control->addRenderView('applyForMember');
//        }

        if ($sender->isLinkClicked(self::Show_Approve_Membership)||$control->isLinkClicked(self::Show_Approve_Membership)) {
            $this->addChildControl($control);
            $control->addRenderView('approveMember');
        }

        if ($sender->isLinkClicked(self::Show_Delete_Membership)) {
            $this->addChildControl($control);
            $control->addRenderView('deleteMember');
        }

        if ($sender->isLinkClicked(self::Show_Admin_Membership) || $control->isLinkClicked(self::Show_Admin_Membership)) {
            $this->addChildControl($control);
            $memberRole = Blyn::app()->getActiveSpace()->getSpaceEngine()->getRole(BRole::Role_App_Member);
            $customerRole = Blyn::app()->getActiveSpace()->getSpaceEngine()->getRole(BRole::Role_App_customer);
            $allRole = BRole::find(BRole::All_Roles);

            $memberRoleData = $this->getAllowApplyRoleData($memberRole);
            $customerRoleData = $this->getAllowApplyRoleData($customerRole);
            $allRoleData = $this->getAllowApplyRoleData($allRole);

            $viewData = array();
            if ($memberRoleData)
                $viewData['memberRoleData'] = $memberRoleData;
            if ($customerRoleData)
                $viewData['customerRoleData'] = $customerRoleData;
            if ($allRoleData)
                $viewData['allRoleData'] = $allRoleData;
            $control->addRenderView('adminMembership', 'adminMembership', $viewData);
        }

        if ($sender->isAjaxLinkClicked(self::Show_ApplyFor_Membership)) {
            $updateControl->addRenderView('applyForMember');
        }

        if ($sender->isAjaxLinkClicked(self::Show_Approve_Membership)) {
            //todo list: need check permit first
            $updateControl->addRenderView('approveMember');
        }

        if ($sender->isAjaxLinkClicked(self::Show_Admin_Membership)) {
            $memberRole = Blyn::app()->getActiveSpace()->getSpaceEngine()->getRole(BRole::Role_App_Member);
            $customerRole = Blyn::app()->getActiveSpace()->getSpaceEngine()->getRole(BRole::Role_App_customer);
            $allRole = BRole::find(BRole::All_Roles);

            $memberRoleData = $this->getAllowApplyRoleData($memberRole);
            $customerRoleData = $this->getAllowApplyRoleData($customerRole);
            $allRoleData = $this->getAllowApplyRoleData($allRole);

            $viewData = array();
            if ($memberRoleData)
                $viewData['memberRoleData'] = $memberRoleData;
            if ($customerRoleData)
                $viewData['customerRoleData'] = $customerRoleData;
            if ($allRoleData)
                $viewData['allRoleData'] = $allRoleData;
            $updateControl->addRenderView('adminMembership', 'adminMembership', $viewData);
        }

        if ($sender->isAjaxLinkClicked(self::Approve_Apply)) {
            //todo list: need check permit first
            $requestItem = $activeLink->getLinkVariable('reqId');
            $userId = $activeLink->getLinkVariable('userId');
            $roleId = $activeLink->getLinkVariable('roleId');
            $requestId = $activeLink->getLinkVariable('messageId');
            /*
              $requestId = $requestItem['messageId'];
              $roleId = $requestItem['roleId'];
              $userId = $requestItem['userId'];
             * 
             */
            if ($userId > 0) {
                $receiver = new BUser($userId);
                $userName = $receiver->getName();
            } else
                $userName = NULL;

            if ($requestId != NULL) {
                if ($requestId > 0) {
                    //add role
                    $messageTable = new BMessageSheet('message');
                    $messageList = $messageTable->getListById($requestId);
                    $messageNameItem = $messageList->getItem('name');
                    if ($messageNameItem) {
                        $messageName = $messageNameItem->getValue();
                    }

                    if ($messageName === 'applyJoinSpace') {
                        $messageStatusItem = $messageList->getItem('messageStatus');

                        if ($messageStatusItem) {
                            $messageStatus = $messageStatusItem->getValue();

                            if ($messageStatus != 'approved' && $messageStatus != 'rejected') {
                                $result = 'approved';
                                $messageStatusItem->save($result);
                                $receiver = new BUser($userId);
                                $receiver->addRole($roleId);
                            }
                        } else {
                            $result = 'approved';
                            $messageList->addItem('messageStatus', $result);
                            $receiver = new BUser($userId);
                            $receiver->addRole($roleId);
                        }
                    }
                }
            }

            $updateControl->addRenderView('approveMember', 'approveMember', array(
                'applyResult' => $result, 'userName' => $userName));
        }

        if ($sender->isAjaxLinkClicked(self::Reject_Apply)) {
            //todo list: need check permit first
            $requestItem = $activeLink->getLinkVariable('reqId');
            $requestId = $requestItem['messageId'];
            $roleId = $requestItem['roleId'];
            $userId = $requestItem['userId'];
            if ($userId > 0) {
                $receiver = new BUser($userId);
                $userName = $receiver->getName();
            } else
                $userName = NULL;

            if ($requestId != NULL) {
                if ($requestId > 0) {
                    if ($roleId > 0)
                        Blyn::app()->getCurrentUser()->rejectMember($roleId);
                    $messageTable = new BMessageSheet('message');
                    $messageList = $messageTable->getListById($requestId);
                    $messageNameItem = $messageList->getItem('name');
                    if ($messageNameItem) {
                        $messageName = $messageNameItem->getValue();
                    }

                    if ($messageName === 'applyJoinSpace') {
                        $messageStatusItem = $messageList->getItem('messageStatus');

                        if ($messageStatusItem) {
                            $messageStatus = $messageStatusItem->getValue();

                            if ($messageStatus != 'rejected') {
                                $result = 'rejected';
                                $messageStatusItem->save($result);
                            }
                        } else {
                            $result = 'rejected';
                            $messageList->addItem('messageStatus', $result);
                        }
                    }
                }
            }

            $updateControl->addRenderView('approveMember', 'approveMember', array(
                'applyResult' => $result, 'userName' => $userName));
        }

        if ($sender->isAjaxLinkClicked(self::Show_Delete_Membership)) {
            $updateControl->addRenderView('deleteMember');
        }

        if ($sender->isAjaxLinkClicked(self::Delete_Apply)) {
            $requestItem = $activeLink->getLinkVariable('reqId');
            $requestId = $requestItem['messageId'];
            $roleId = $requestItem['roleId'];
            $userId = $requestItem['userId'];
            $userId = $activeLink->getLinkVariable('userId');
            $roleId = $activeLink->getLinkVariable('roleId');
            $requestId = $activeLink->getLinkVariable('messageId');
            if ($userId > 0) {
                $receiver = new BUser($userId);
                $userName = $receiver->getName();
            } else
                $userName = NULL;

            $removeUserRoleId = $requestId;
            if ($removeUserRoleId > 0 && $userId > 0) {
                $data = array('userId' => $userId);
                Blyn::app()->getCurrentUser()->removeRole($removeUserRoleId, $data);

                $operation = Blyn::app()->getActiveOperation();
                $app = $operation->getCurrentApp();
                $space = $app->getCurrentSpace();
                $userData = array();
                //send user a remove role message
                $userData['userId'] = $userId;
                $userData['name'] = 'manageMember';
                $sender_Space = $space->getName();
                $roleToJoin = new BRole($roleId);
                $userData['content'] = $sender_Space . ' ' . Yii::t('site', 'Role') . ' ' . Yii::t('site', $roleToJoin->name) . ' : ' . Yii::t('site', 'Remove');
                $operation->getMessenger()->sendMessage('manageMember', NULL, $userData);
                $result = 'deleted';
            }

            $updateControl->addRenderView('deleteMember', 'deleteMember', array(
                'applyResult' => $result, 'userName' => $userName));
        }

        if ($sender->isAjaxLinkClicked('nextSpaceUser') ||
                $sender->isAjaxLinkClicked('previousSpaceUser')) {
            $joinedUsers = $activeLink->getLinkVariable('joinedUsers');
            $current_index = $activeLink->getLinkVariable('current_index');
            $updateControl->addRenderView('deleteMember_1', 'deleteMember_1', array('joinedUsers' => $joinedUsers,
                'current_index' => $current_index));
        }

        if ($sender->isAjaxLinkClicked(self::Submit_Apply)) {
            $postManager = new BPostManager();
            $postData = $postManager->parsedModelData();
            $mediaList = $postManager->populateMediaListFromPostData($postData, 'membership');
            $user = Blyn::app()->getCurrentUser();

            $roleId = $mediaList['roleId']->getContent();

            if (is_numeric($roleId) && $roleId > 0) {
                //below send message
                $userData['userId'] = $user->id;
                $userData['roleId'] = $roleId;
                $personalApp = $user->getPersonalSpace()->getAppByName('BPersonalApp');
                $applyResult = $personalApp->getOperation('applyJoinSpace')->getMessenger()->
                        sendMessage('applyJoinSpace', NULL, $userData);
            }

            if (isset($applyResult) && $applyResult != NULL) {
                $updateControl->addRenderView('applyForMember', 'applyForMember', array(
                    'applyResult' => $applyResult
                ));
            } else {
                $updateControl->addRenderView('applyForMember', 'applyForMember', array(
                    'applyResult' => 'fail'
                ));
            }
        }

        if ($sender->isAjaxLinkClicked(self::Add_Allow_Apply_Role)) {
            $postManager = new BPostManager();
            $postData = $postManager->parsedModelData();

            $mediaList = $postManager->populateMediaListFromPostData($postData, 'admin_membership');

            $memberList = $mediaList['memberList']->content;
            $customerList = $mediaList['customerList']->content;
            $allRoleList = $mediaList['allUserList']->content;

            $memberRole = Blyn::app()->getActiveSpace()->getSpaceEngine()->getRole(BRole::Role_App_Member);
            $customerRole = Blyn::app()->getActiveSpace()->getSpaceEngine()->getRole(BRole::Role_App_customer);
            $allRole = BRole::find(BRole::All_Roles);

            $addRoleResult = 'success';
            if (is_array($memberList)) {
                foreach ($memberList as $roleId) {
                    $role = new BRole($roleId);
                    $addResult = $this->addAllowApplyRole($memberRole, $role);
                    if ($addResult == FALSE)
                        $addRoleResult = FALSE;
                }
            }

            if (is_array($customerList)) {
                foreach ($customerList as $roleId) {
                    $role = new BRole($roleId);
                    $addResult = $this->addAllowApplyRole($customerRole, $role);
                    if ($addResult == FALSE)
                        $addRoleResult = FALSE;
                }
            }

            if (is_array($allRoleList)) {
                foreach ($allRoleList as $roleId) {
                    $role = new BRole($roleId);
                    $addResult = $this->addAllowApplyRole($allRole, $role);
                    if ($addResult == FALSE)
                        $addRoleResult = FALSE;
                }
            }

            $memberRoleData = $this->getAllowApplyRoleData($memberRole);
            $customerRoleData = $this->getAllowApplyRoleData($customerRole);
            $allRoleData = $this->getAllowApplyRoleData($allRole);

            $viewData = array('addRoleResult' => $addRoleResult);
            if ($memberRoleData)
                $viewData['memberRoleData'] = $memberRoleData;
            if ($customerRoleData)
                $viewData['customerRoleData'] = $customerRoleData;
            if ($allRoleData)
                $viewData['allRoleData'] = $allRoleData;

            $updateControl->addRenderView('adminMembership', 'adminMembership', $viewData);
        }

        if ($sender->isAjaxLinkClicked(self::Show_User_Membership)) {
            $updateControl->addRenderView('userMembership');
        }
    }

    protected function addAllowApplyRole($origRole, $allowRole) {
        if ($origRole instanceof BRole) {
            $allowRoleTable = new BSheet('allowApplyRole', $origRole);
            $appId = $allowRole->appId;
            $appClass = 'BApp';
            if ($appId > 0) {
                $app = BApp::getAppById($appId);
                $appClass = get_class($app);
            }
            if ($allowRole instanceof BRole) {
                $roleId = $allowRole->getId();
                $roleName = $allowRole->getName();
                $fullName = $allowRole->getFullName();
                $roleData = array(
                    'roleId' => $roleId,
                    'roleName' => $roleName,
                    'roleFullName' => $fullName,
                    'appId' => $appId,
                    'appClass' => $appClass);
                if (!$allowRoleTable->getList(array('itemData' => $roleData))) {
                    return $allowRoleTable->addList($roleData);
                }
            }
        }
        return FALSE;
    }

    /**
     * this function populate all available allow role for all roles in space
     * data is saved into table of 'availableApplyRole' table
     * @param type $data
     */
    public function populateAvailableApplyRole($data = NULL) {

        $space = Blyn::app()->getActiveSpace();
        $isPopulatedApplyRolesAttr = $space->getAttribute('isPopulatedApplyRoles');
        //$isPopulatedApplyRolesAttr = NULL;
        if ($isPopulatedApplyRolesAttr == NULL || $isPopulatedApplyRolesAttr->getValue() != 'yes') {
            $apps = $space->getApps();
            $spaceEngine = Blyn::app()->getActiveSpace()->getSpaceEngine();

            $appCustomer = $spaceEngine->getRole(BRole::Role_App_customer);
            $allCustomerRoles = $appCustomer->getChildren(NULL, TRUE);
            $allCustomerRoles[$appCustomer->getId()] = $appCustomer;

            $appMember = $spaceEngine->getRole(BRole::Role_App_Member);
            $allMemberRoles = $appMember->getChildren(NULL, TRUE);
            $allMemberRoles[$appMember->getId()] = $appMember;

            $appAdmin = $spaceEngine->getRole(BRole::Role_App_Admin);
            $allAdminRoles = $appAdmin->getChildren(NULL, TRUE);
            $allAdminRoles[$appAdmin->getId()] = $appAdmin;

            $allrole = BRole::find(BRole::All_Roles);
            $availableApplyRoleTable = new BSheet('availableApplyRole', $allrole);
            //for all user, can apply any customer roles
            $this->addApplyRole($allrole, $allCustomerRoles, $availableApplyRoleTable);
            //for all user, can also apply any member role
            $this->addApplyRole($allrole, $allMemberRoles, $availableApplyRoleTable);

            foreach ($apps as $app) {
                if ($app instanceof BApp) {
                    $roles = $app->getRoles();
                    if ($roles != NULL) {
                        foreach ($roles as $id => $role) {
                            $availableApplyRoleTable = new BSheet('availableApplyRole', $role);
                            $roleData[$id] = $app->getName() . '|' . $role->getName();
                            $fullName = $role->getFullName();
                            if (strpos($fullName, 'app_customer')) {//customer role
                                //for customer role, allow join roles can be any child role
                                $customerChildren = $role->getChildren(NULL, TRUE);
                                $this->addApplyRole($role, $customerChildren, $availableApplyRoleTable);

                                //for customer role, also can apply any member roles
                                $this->addApplyRole($role, $allMemberRoles, $availableApplyRoleTable);
                            }

                            if (strpos($fullName, 'app_member')) {//customer role
//for member role, allow join roles can be any parent role
                                $memberParents = $role->getParent(TRUE);
                                foreach ($memberParents as $key => $aRole) {
                                    if ($aRole->getName() == 'root' || $aRole->getName() == 'app_root')
                                        unset($memberParents[$key]);
                                }
                                $this->addApplyRole($role, $memberParents, $availableApplyRoleTable);

//for member role, also can apply any admin roles
                                $this->addApplyRole($role, $allAdminRoles, $availableApplyRoleTable);
                            }

                            if (strpos($fullName, 'app_admin')) {//customer role
//for admin role, allow join roles can be any parent role
                                $adminParents = $role->getParent(TRUE);
                                foreach ($adminParents as $key => $aRole) {
                                    if ($aRole->getName() == 'root' || $aRole->getName() == 'app_root')
                                        unset($adminParents[$key]);
                                }
                                $this->addApplyRole($role, $adminParents, $availableApplyRoleTable);
                            }
                        }
                    }
                }
            }
            $space->addAttribute('isPopulatedApplyRoles', 'yes');
        }
    }

    /**
     * this function will first populate user's role
     * then populate allow apply role for user
     * user's allow apply role save to table of 'allowApplyRole'
     * @param type $data
     */
    public function getUserAllowApplyRoles($data = NULL) {
        $userRoles = BRole::findUserRoles(NULL, array('spaceId' => Blyn::app()->getActiveSpace()->getId()));
        $allowRoleData = array();

        //$availableApplyRoles = new BSheet('allowApplyRole', $role);
        //below code will foreach all user's role, 
        //then find all allow apply roles for user's role
        //finally get all allow apply roles for user,
        //all allowApplyRole is saved into allowApplyRole table
        foreach ($userRoles as $id => $role) {
            $roleFullName = $role->getFullName();
            //default for all child customer
            if (strpos($roleFullName, 'app_customer') != FALSE) {
                $children = $role->getChildren(NULL, TRUE);
                foreach ($children as $roleId => $role) {
                    $roleName = $role->getName();
                    $fullName = $role->getFullName();
                    if ($fullName == 'app_root' || $fullName == 'root')
                        continue;
                    $appId = $role->appId;
                    $appClass = 'BApp';
                    if ($appId > 0) {
                        $app = BApp::getAppById($appId);
                        $appClass = get_class($app);
                    }
                    $alias = BUIRole::getRoleAliasByFullName($fullName);
                    if (!$alias)
                        $alias = $roleName;
                    $allowRoleData[$roleId] = $appClass . '::' . $alias;
                }
            }
            //default for all parent of admin and member
            if (strpos($roleFullName, 'app_admin') !== FALSE || strpos($roleFullName, 'app_member') !== FALSE) {
                $parents = $role->getParent(TRUE);
                foreach ($parents as $roleId => $role) {
                    $roleName = $role->getName();
                    $fullName = $role->getFullName();
                    if ($fullName == 'app_root' || $fullName == 'root')
                        continue;
                    $appId = $role->appId;
                    $appClass = 'BApp';
                    if ($appId > 0) {
                        $app = BApp::getAppById($appId);
                        $appClass = get_class($app);
                    }
                    $alias = BUIRole::getRoleAliasByFullName($fullName);
                    if (!$alias)
                        $alias = $roleName;
                    $allowRoleData[$roleId] = $appClass . '::' . $alias;
                }
            }
            $aTable = new BSheet('allowApplyRole', $role);
            $aView = $aTable->getView();
            foreach ($aView as $list) {
                $roleId = $list->getItem('roleId')->getValue();
                $fullName = $list->getItem('roleFullName')->getValue();
                $roleName = $list->getItem('roleName')->getValue();
                $appClass = $list->getItem('appClass')->getValue();
                $alias = BUIRole::getRoleAliasByFullName($fullName);
                if (!$alias)
                    $alias = $roleName;
                $allowRoleData[$roleId] = $appClass . '::' . $alias;
            }
        }
        return $allowRoleData;
    }

    protected function addApplyRole($role, $applyRoleList, $roleTable) {
        foreach ($applyRoleList as $aRole) {
            if ($role instanceof BRole && $aRole instanceof BRole) {
                $appId = $aRole->appId;
                $appClass = 'BApp';
                if ($appId > 0) {
                    $app = BApp::getAppById($appId);
                    $appClass = get_class($app);
                }
                $roleData = array(
                    'roleId' => $role->getId(),
                    'roleName' => $role->getName(),
                    'roleFullName' => $role->getFullName(),
                    'applyRoleId' => $aRole->getId(),
                    'applyRoleName' => $aRole->getName(),
                    'applyRoleFullName' => $aRole->getFullName(),
                    'appId' => $appId,
                    'appClass' => $appClass
                );
                if (!$roleTable->getList(array('itemData' => $roleData))) {
                    $roleTable->addList($roleData);
                }
            }
        }
    }

    protected function getAllowApplyRoleData($ownRole) {
        if ($ownRole instanceof BRole) {
            $allowRoleTable = new BSheet('allowApplyRole', $ownRole);
            $roleView = $allowRoleTable->getView();
            $roleData = array();
            foreach ($roleView as $list) {
                $roleId = $list->getItem('roleId')->getValue();
                $fullName = $list->getItem('roleFullName')->getValue();
                $roleData[$fullName] = $roleId;
            }
            return $roleData;
        }
        return FALSE;
    }

}
